/*
 * ManejadorArchivoUnico.cpp
 *
 *  Created on: 10/09/2010
 *      Author: julfc
 */

#include "ManejadorArchivoUnico.h"

ManejadorArchivoUnico::ManejadorArchivoUnico(){

}

ManejadorArchivoUnico::ManejadorArchivoUnico(char* nombreArchivo, AbrirCrearArchivo abrirCrear) :
  ManejadorAccesoDatos(nombreArchivo, abrirCrear) {

}

long ManejadorArchivoUnico::escribirMail(long uid, char* cadena, long tam_mail_serv) {
	//Se fija si hay espacio en algun bloque existente.
	long tamanio_maximo_mail = getTamanioBloques() - 16;
	//Trunca el mail si es necesario.
	long tamanio_mail = tam_mail_serv;
	if (tamanio_mail > tamanio_maximo_mail) {
		tamanio_mail = tamanio_maximo_mail;
	}
	//cout << "El tamanio del mail es: " << tamanio_mail <<"\n";

	//FIXME Al no poder hacer el puto free en el siguiente metodo la memoria se va a la mierda.
	long nro_bloque = buscarEspacioEnBloques(tamanio_mail);

	//Inicializo las variables.
	char* bloque;
	char* aux_bloque;
	long tamanio_bloque = getTamanioBloques();
	long cant_mails = 0;
	long esp_libre_bloque = 0;

	if (nro_bloque < 0) {
		//Tengo que creabloquer un bloque nuevo
		nro_bloque = getCantidadBloques();
		//cout << " \n\n No hay espacio libre en el bloque, se creo el bloque " << nro_bloque << "\n\n";
		bloque = inicillizarBloque(tamanio_bloque);
		aux_bloque = bloque;
		//Guardo espacio libre (total - tamanioMail - 16 (cant mails + esp_libre + uid + tamanio)).
		esp_libre_bloque = tamanio_bloque - tamanio_mail - 16;
		cant_mails = 1;
		memcpy(aux_bloque, &cant_mails, sizeof(long));
		aux_bloque+=sizeof(long);
		memcpy(aux_bloque, &esp_libre_bloque, sizeof(long));
		aux_bloque+=sizeof(long);
	} else {
		//cout << " \n\n Hay espacio libre en el bloque " << nro_bloque << "\n\n";

		bloque = leerBloque(nro_bloque);
		aux_bloque = bloque;

		memcpy(&cant_mails, aux_bloque, sizeof(long));
		cant_mails++;
		memcpy(aux_bloque, &cant_mails, sizeof(long));
		aux_bloque+=sizeof(long);
		memcpy(&esp_libre_bloque, aux_bloque, sizeof(long));
		long index = tamanio_bloque - esp_libre_bloque;
		esp_libre_bloque = esp_libre_bloque - tamanio_mail - (2*sizeof(long));
		memcpy(aux_bloque, &esp_libre_bloque, sizeof(long));
		aux_bloque = bloque;
		aux_bloque+= (index);
	}

	//cout << " \n\n El bloque " << nro_bloque << " tiene  " << esp_libre_bloque << " bytes libres en el bloque\n\n";

	memcpy(aux_bloque, &uid, sizeof(long));
	aux_bloque+=sizeof(long);
	memcpy(aux_bloque, &tamanio_mail, sizeof(long));
	aux_bloque+=sizeof(long);
	memcpy(aux_bloque, cadena, tamanio_mail);
	aux_bloque+=sizeof(cadena);
	escribir(bloque, nro_bloque);
	//cout << " \n\n El mail " << uid << " se escribio en el bloque " << nro_bloque << "\n\n";
	free(bloque);
	return nro_bloque;
}

char* ManejadorArchivoUnico::obtenerMail(long uid, long nro_bloque) {
	char* bloque = leerBloque(nro_bloque);
	char* aux_bloque = bloque;
	long cant_mails = 0;
	bool encontrado = false;
	char* mail;

	memcpy(&cant_mails, aux_bloque, sizeof(long));
	//Me salteo el espacio libre en el bloque.
	aux_bloque+=2*sizeof(long);

	long i = 1;

	while (i <= cant_mails && !encontrado) {
		long uidAux = 0;
		long tamanioMail = 0;

		memcpy(&uidAux, aux_bloque, sizeof(long));
		aux_bloque+=sizeof(long);
		memcpy(&tamanioMail, aux_bloque, sizeof(long));
		aux_bloque+=sizeof(long);

		if (uidAux == uid ) {
			encontrado = true;
			mail = (char*) malloc(tamanioMail + 1);
			mail[tamanioMail]='\0';
			memcpy(mail,aux_bloque,tamanioMail);
		} else {
			aux_bloque+= tamanioMail;
			i++;
		}
	}
	free(bloque);
	if (encontrado) return mail;
	return NULL;
}

FiltroSeleccion ManejadorArchivoUnico::buscarValoresFiltroSeleccion(DatoAObtener clave, string valor) {
	FiltroSeleccion filtroSeleccion;
	filtroSeleccion.clave = valor;

	long cantBloques = getCantidadBloques();
	long j = 0;

	while (j < cantBloques) {
		char* bloque;
		char* auxBloque;
		long cantMails = 0;
		bloque = leerBloque(j);
		auxBloque = bloque;
		memcpy(&cantMails, auxBloque, sizeof(long));
		//Me salteo el espacio libre en el bloque.
		auxBloque+=2*sizeof(long);
		long i = 1;
		while (i <= cantMails) {
			char* mail;
			long uid = 0;
			long tamanioMail = 0;
			memcpy(&uid, auxBloque, sizeof(long));
			auxBloque+=sizeof(long);
			memcpy(&tamanioMail, auxBloque, sizeof(long));
			auxBloque+=sizeof(long);
			mail = (char*) malloc(tamanioMail + 1);
			mail[tamanioMail]='\0';
			memcpy(mail,auxBloque,tamanioMail);
			//Me fijo si matchea y lo agrego.
			bool match = procesarFiltroMail(clave, valor, mail);
			if (match) {
				filtroSeleccion.valores.push_back(uid);
			}
			auxBloque+= tamanioMail;
			i++;
			free(mail);
		}
		free(bloque);
		j++;
	}
	return filtroSeleccion;
}


vector<FiltroSeleccion> ManejadorArchivoUnico::buscarValoresFiltroClasificacion(DatoAObtener clave) {
	vector<FiltroSeleccion> listaFiltros;

	long cantBloques = getCantidadBloques();
	long j = 0;

	while (j < cantBloques) {
		char* bloque;
		char* auxBloque;
		long cantMails = 0;
		bloque = leerBloque(j);
		auxBloque = bloque;
		memcpy(&cantMails, auxBloque, sizeof(long));
		//Me salteo el espacio libre en el bloque.
		auxBloque+=2*sizeof(long);
		long i = 1;
		while (i <= cantMails) {
			char* mail;
			long uid = 0;
			long tamanioMail = 0;
			memcpy(&uid, auxBloque, sizeof(long));
			auxBloque+=sizeof(long);
			memcpy(&tamanioMail, auxBloque, sizeof(long));
			auxBloque+=sizeof(long);
			mail = (char*) malloc(tamanioMail + 1);
			mail[tamanioMail]='\0';
			memcpy(mail,auxBloque,tamanioMail);
			//Lo agrego a la lista de filtros.
			agregarMailFiltroClasificaion(listaFiltros, clave, mail, uid);
			auxBloque+= tamanioMail;
			i++;
			free(mail);
		}
		free(bloque);
		j++;
	}
	return listaFiltros;
}

void ManejadorArchivoUnico::agregarMailFiltroClasificaion(vector<FiltroSeleccion> &listaFiltros, DatoAObtener clave, char* mail, long uid) {
	Mail mailClass;
	string mailStr = mailClass.mailToString(mail);
	vector<string> listaTo;
	string dato;
	switch (clave) {
		case DATE:
			dato = mailClass.getDate(mailStr);
			agregarMailAListaFiltros(listaFiltros, dato, uid);
			break;
		case SUBJECT:
			dato = mailClass.getSubject(mailStr);
			agregarMailAListaFiltros(listaFiltros, dato, uid);
			break;
		case FROM:
			dato = mailClass.getFrom(mailStr);
			agregarMailAListaFiltros(listaFiltros, dato, uid);
			break;
		case TO:
			listaTo = mailClass.getTo(mailStr);
			for (unsigned int i = 0; i < listaTo.size(); i++) {
				agregarMailAListaFiltros(listaFiltros, listaTo[i], uid);
			}
			listaTo = mailClass.getCc(mailStr);
			for (unsigned int j = 0; j < listaTo.size(); j++) {
				agregarMailAListaFiltros(listaFiltros, listaTo[j], uid);
			}
			break;
		default:
			break;
	}
}

void ManejadorArchivoUnico::agregarMailAListaFiltros (vector<FiltroSeleccion> &listaFiltros, string clave, long uid) {
	bool encontrado = false;
	for(unsigned int i = 0; i < listaFiltros.size() && !encontrado; i++) {
		if (clave.compare(listaFiltros[i].clave) == 0) {
			encontrado = true;
			listaFiltros[i].valores.push_back(uid);
		}
}
	if (!encontrado) {
		FiltroSeleccion filtroAgregar;
		filtroAgregar.clave = clave;
		filtroAgregar.valores.push_back(uid);
		listaFiltros.push_back(filtroAgregar);
	}
}


bool ManejadorArchivoUnico::procesarFiltroMail(DatoAObtener clave, string valor, char* mail) {
	Mail mailClass;
	string mailStr = mailClass.mailToString(mail);
	string dato;
	switch (clave) {
	    case DATE:
	      dato = mailClass.getDate(mailStr);
	      return (dato.find(valor) != 0);
	      break;
	    case SUBJECT:
	      dato = mailClass.getSubject(mailStr);
	      return (dato.find(valor) != -1);
	      break;
	    case FROM:
	      dato = mailClass.getFrom(mailStr);
	      return (dato.compare(valor) == 0);
	      break;
	    case TO:
	      return procesarTo(mailStr, valor);
	      break;
	    default:
	      return NULL;
	      break;
	}
}

bool ManejadorArchivoUnico::procesarTo(string mailStr, string valor) {
	Mail claseMail;
	vector<string> to;
	vector<string> cc;
	to = claseMail.getTo(mailStr);
	cc = claseMail.getCc(mailStr);
	for (unsigned i = 0; i < to.size(); i++) {
		int igual = valor.compare(to[i]);
		if (igual == 0) return true;
	}
	for (unsigned j = 0; j < cc.size(); j++) {
		int igual = valor.compare(cc[j]);
		if (igual == 0) return true;
	}
	return false;
}

ManejadorArchivoUnico::~ManejadorArchivoUnico() {

}
